package client

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"gitee.com/baizhige/go-server-tempalte/common/constant"
	"gitee.com/baizhige/go-server-tempalte/common/log"
	"gitee.com/baizhige/go-server-tempalte/common/redis"
	"gitee.com/baizhige/go-server-tempalte/util/random"
	"github.com/gin-gonic/gin"
)

// private.go 私有方法

// aESBase64Dec AES 解密base64编码的密文
// 传入的密文应该为base编码，解码后得到的应该是iv+密文
func aESBase64Dec(ct, key string) (res string, err error) {
	// 创建密码器
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		log.Error("create the block error, key invalid :%s", key)
		return "", constant.ErrClientKeyIsInvalid
	}
	// base64解码
	ciphertext, err := base64.StdEncoding.DecodeString(ct)
	if err != nil {
		log.ErrorF("Decode string error, the string is %s, error is %s", ct, err.Error())
		return
	}
	// 获取iv和密文
	if len(ciphertext) < aes.BlockSize {
		err = fmt.Errorf("the length of the ciphertext is too short")
		log.ErrorF("%v", err)
		return
	}
	iv := ciphertext[:aes.BlockSize]
	ciphertext = ciphertext[aes.BlockSize:]
	// 解密
	stream := cipher.NewCFBDecrypter(block, iv)
	stream.XORKeyStream(ciphertext, ciphertext)
	return string(ciphertext), nil
}

// aESBase64Enc AES 加密成base64编码
// 随机生成iv
// iv拼在密文前面，然后做整体base64返回
func aESBase64Enc(pt, key string) (string, error) {
	// 创建密码器
	block, err := aes.NewCipher([]byte(key))
	if err != nil {
		log.Error("create the block error, key invalid :%s", key)
		return "", constant.ErrClientKeyIsInvalid
	}
	// 生成随机偏移量
	plaintext := []byte(pt)
	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	iv := ciphertext[:aes.BlockSize]

	//生成IV
	bytes := []byte(random.Crypto(16))
	for index, _ := range iv {
		iv[index] = bytes[index]
	}

	// 加密
	stream := cipher.NewCFBEncrypter(block, iv)
	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
	// base64 编码
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

func getClientKey(traceID string, c *gin.Context) (clientKey string, err error) {
	clientId, err := GetId(traceID, c)
	if err != nil {
		return
	}
	//获取通信密钥
	redisKey := fmt.Sprintf(constant.CacheClientSecretKey, clientId)
	clientKey, err = redis.Get(redisKey)
	if err != nil {
		log.ErrorTF(traceID, "client key get by redis fail:%v,key:%s", err, redisKey)
	}
	log.InfoTF(traceID, "client key is:%s", redisKey)
	return
}

// rSADecryptBase64 RSA 解密 Base64 密文
func rSADecryptBase64(b64Cipher string) ([]byte, error) {
	cipherText, err := base64.StdEncoding.DecodeString(b64Cipher)
	if err != nil {
		log.ErrorTF("base64.StdEncoding.DecodeString error! b64Cipher:%s, err:%s", b64Cipher, err)
		return nil, err
	}

	priv, err := parsePKCS1Or8PrivKey(privateKey)
	if err != nil {
		return nil, err
	}

	return rsa.DecryptPKCS1v15(rand.Reader, priv, cipherText)
}

func parsePKCS1Or8PrivKey(key []byte) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode(key)
	if block == nil {
		return nil, errors.New("priv key error")
	}
	var privKey *rsa.PrivateKey
	privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err == nil {
		return privKey, nil
	}

	privKeyInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err == nil {
		if priKey, ok := privKeyInterface.(*rsa.PrivateKey); ok {
			return priKey, nil
		}
	}
	return nil, errors.New("parse private key error")
}
